package com.docMan.lucene;

import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.sql.Date;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.lucene.analysis.cn.smart.SmartChineseAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.document.LongField;
import org.apache.lucene.document.NumericDocValuesField;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.DocValuesType;
import org.apache.lucene.index.IndexOptions;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;

import com.docMan.bean.IndexFile;
import com.docMan.utils.CastUtil;
import com.docMan.utils.FinalConfig;
import com.docMan.utils.GetRealPath;
import com.docMan.utils.PoiUtils;

public class Indexer {
	public static final FieldType TYPE_STORED = new FieldType();
	static {
		TYPE_STORED.setTokenized(true);
		TYPE_STORED.setOmitNorms(true);
		TYPE_STORED.setIndexOptions(IndexOptions.DOCS);
		TYPE_STORED.setNumericType(FieldType.NumericType.LONG);
		TYPE_STORED.setDocValuesType(DocValuesType.NUMERIC);
		TYPE_STORED.setStored(true);
		TYPE_STORED.freeze();
	}
	private String indexDir;
	private IndexWriter writer;
	private static Indexer indexer;
	private Searcher searcher;

	public Indexer(String indexDir) throws IOException {
		super();
		this.indexDir = indexDir;
		File file = new File(indexDir);
		if (!file.exists())
			file.mkdirs();
		Directory directory = FSDirectory.open(Paths.get(indexDir));
		SmartChineseAnalyzer analyzer = new SmartChineseAnalyzer();
		IndexWriterConfig iwc = new IndexWriterConfig(analyzer);
		iwc.setMaxBufferedDocs(100);
		this.writer = new IndexWriter(directory, iwc);
	}

	public synchronized static Indexer getInstance(String indexDir)
			throws IOException {
		if (null == indexer) {
			indexer = new Indexer(indexDir);
			return indexer;
		} else {
			return indexer;
		}
	}

	public void close() throws IOException {
		// writer.close();
	}

	/**
	 * 
	 * @param f
	 * @param fileId
	 * @param indexFile
	 * @throws Exception
	 */
	public void indexFile(File f, String fileId, IndexFile indexFile)
			throws Exception {
		Document document = getDocument(f, fileId, indexFile);
		writer.addDocument(document);
		writer.commit();
		System.out.println("索引文件：" + f.getCanonicalPath() + "-时间"
				+ System.currentTimeMillis() + "已经索引的数量：" + writer.numDocs());
	}

	/**
	 * 对OA数据库中的文件做索引
	 * 
	 * @param fileId
	 * @param indexFile
	 * @return
	 */
	public void indexOAFile(IndexFile indexFile) throws IOException {
		Document document = getDocumentOA(indexFile);
		writer.addDocument(document);
		writer.commit();
		System.out.println("索引文件：fileId" + indexFile.getFileId() + "已经索引的数量："
				+ writer.numDocs());
	}

	private Document getDocumentOA(IndexFile indexFile) {
		Document document = new Document();
		// document.add(new TextField("contents", new FileReader(f)));
		document.add(new TextField("fileName", indexFile.getFileName(),
				Field.Store.YES));
		// document.add(new StringField("fileNameString",
		// indexFile.getFileName(), Field.Store.YES));
		document.add(new StringField("id", indexFile.getFileId(),
				Field.Store.YES));
		document.add(new TextField("swbh", indexFile.getSWBH(), Field.Store.YES));// 收文编号需要索引
		document.add(new StringField("createTime", indexFile.getCreateTime(),
				Field.Store.YES));
		document.add(new TextField("lwbh", indexFile.getLWBH(), Field.Store.YES));// 来文编号需要索引
		document.add(new StringField("lwdw", indexFile.getLWDW(),
				Field.Store.YES));
		document.add(new TextField("content", indexFile.getContent(),
				Field.Store.YES));
		document.add(new StringField("indexFrom", FinalConfig.INDEX_FORM_OA,
				Field.Store.YES));
		document.add(new StringField("imageCssClass", "file_pdf_ico_d32",
				Field.Store.YES));
		// 需要进行排序的字段需要用NumericDocValuesField
//		document.add(new LongField("date", indexFile.getDate().getTime(),TYPE_STORED));
		document.add(new StringField("searchable", CastUtil
				.castString(FinalConfig.searchable_range_all), Field.Store.YES));
		document.add(new NumericDocValuesField("date", indexFile.getDate().getTime()));
		document.add(new StringField("isImportantFile", indexFile
				.getIsImportantFile(), Field.Store.YES));
		// TODO document.add(new StringField("display", indexFile, stored));
		// document.add(new LongField("nd",
		// ProjectUtils.getYear(indexFile.getDate()), Field.Store.YES));
		// TODO
		// document.add(new StringField("fileType", , stored));
		return document;
	}

	private Document getDocument(File f, String fileId, IndexFile indexFile)
			throws Exception {
		Document document = new Document();
		// document.add(new TextField("contents", new FileReader(f)));
		document.add(new TextField("fileName", f.getName(), Field.Store.YES));
		document.add(new StringField("fileNameString", f.getName(),
				Field.Store.YES));
		document.add(new StringField("id", fileId, Field.Store.YES));
		document.add(new StringField("humanName", indexFile.getHumanName(),
				Field.Store.YES));
		document.add(new StringField("createTime", indexFile.getCreateTime(),
				Field.Store.YES));
		document.add(new StringField("imageCssClass", indexFile
				.getImageCssClass(), Field.Store.YES));
		document.add(new TextField("content", PoiUtils
				.getFileContentOnlyText(f), Field.Store.YES));
		document.add(new NumericDocValuesField("date", indexFile.getDate()
				.getTime()));

		// document.add(new
		// LongField("nd",ProjectUtils.getYear(indexFile.getDate()),Field.Store.YES));
		document.add(new StringField("indexFrom",
				FinalConfig.INDEX_FORM_UPLOAD, Field.Store.YES));
		document.add(new StringField("searchable", indexFile.getSearchAble(),
				Field.Store.YES));
		if (indexFile.getSearchAble().equals(
				FinalConfig.searchable_range_unit + "")) {
			document.add(new StringField("unitId", indexFile.getUnitId(),
					Field.Store.YES));
		} else if (indexFile.getSearchAble().equals(
				FinalConfig.searchable_range_humans + "")) {
			document.add(new StringField("humanIds", indexFile.getHumanIds(),
					Field.Store.YES));
		}
		// document.add(new StringField("fileType",
		// getFileType(indexFile.getImageCssClass()), Field.Store.YES));
		try {
			document.add(new StringField("path", GetRealPath.getPath(indexFile
					.getPathId()), Field.Store.YES));
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return document;
	}

	public void update(String fileId, Map<String, String> fields)
			throws IOException {
		if (searcher == null) {
			searcher = new Searcher(indexDir);
		}
		TopDocs topDocs = searcher.TermQueryL("id", fileId);
		ScoreDoc[] scoreDocs = topDocs.scoreDocs;
		if (scoreDocs.length > 0) {
			Document oldDocument = searcher.getDocument(scoreDocs[0]);
			for (String field : fields.keySet()) {
				oldDocument.removeField(field);
			}
			writer.updateDocument(new Term("id", fileId), oldDocument);
			writer.commit();
			// 当文件索引改变,commit 后要重新reopen 索引，否则搜索到的还是无效的
			searcher.reopen();
			Document newDocument = searcher.getDocument(scoreDocs[0]);
			for (String field : fields.keySet()) {
				newDocument.add(new StringField(field, fields.get(field),
						Field.Store.YES));
			}
			writer.updateDocument(new Term("id", fileId), newDocument);
			writer.commit();
		}
	}
	public void updateBatch(Map<String, Map<String, Object>> updateMap) throws IOException, ParseException{
		if (searcher == null) {
			searcher = new Searcher(indexDir);
		}
		Map<String, Object> fields=null;
		for(String fileId:updateMap.keySet()){
			fields=updateMap.get(fileId);
			TopDocs topDocs = searcher.TermQueryL("id", fileId);
			ScoreDoc[] scoreDocs = topDocs.scoreDocs;
			if (scoreDocs.length > 0) {
				Document oldDocument = searcher.getDocument(scoreDocs[0]);
				writer.deleteDocuments(new Term("id", fileId));
				String isImportantFile =oldDocument.get("isImportantFile");
						oldDocument.removeField("isImportantFile");
						oldDocument.removeField("date");
						oldDocument.add(new StringField("isImportantFile", fields.get("isImportantFile").toString(),
								Field.Store.YES));
						Date date=(Date) fields.get("date");
						oldDocument.add(new NumericDocValuesField("date", date.getTime()));
					writer.updateDocument(new Term("id", fileId), oldDocument);
//				writer.commit();
			}
		}
		writer.commit();
	}
	
	public void deleteDouble(List<String> fileIds) throws IOException{
		if (searcher == null) {
			searcher = new Searcher(indexDir);
		}
		for (int i = 0; i < fileIds.size(); i++) {
			TopDocs topDocs = searcher.TermQueryL("id", fileIds.get(i));
			ScoreDoc[] scoreDocs = topDocs.scoreDocs;
			if(scoreDocs.length > 1){
				Document oldDocument = searcher.getDocument(scoreDocs[0]);
				writer.deleteDocuments(new Term("id", fileIds.get(i)));
				writer.addDocument(oldDocument);
			}
		}
		writer.commit();
	}
	public void delete(String fileId) throws IOException {
		writer.deleteDocuments(new Term("id", fileId));
		writer.commit();
	}

	private String getFileType(String imageCssClass) {
		if (imageCssClass.contains("word")) {
			return "word";
		} else if (imageCssClass.contains("excel")) {
			return "excel";
		}
		return "excel";
	}

	private String getOaFileType(String fileName) {
		String type = fileName.substring(fileName.lastIndexOf(".") + 1,
				fileName.length());
		return type;
	}
}
